Skip to content

Release MCP 0.6.3#32

Merged
milstan merged 1 commit into
mainfrom
milstan/release-mcp-0.6.3
May 12, 2026
Merged

Release MCP 0.6.3#32
milstan merged 1 commit into
mainfrom
milstan/release-mcp-0.6.3

Conversation

@milstan

@milstan milstan commented May 12, 2026

Copy link
Copy Markdown
Contributor

Summary

  • bump @leadbay/mcp to 0.6.3
  • align MCP Registry server.json metadata with 0.6.3
  • document the async output schema fixes for Claude Desktop/MCP clients

Verification

  • pnpm -r typecheck
  • pnpm -r test

@milstan milstan merged commit df6cee8 into main May 12, 2026
1 check passed
ArtyETH06 added a commit that referenced this pull request Jun 19, 2026
Adds workflow #32 (Modify qualification methods) exercising
leadbay_set_qualification_methods, and drops the now-stale "read-only"
note from #30. Scenario adds a question against an org already at the
5-question cap — exercises the write tool + cap handling while mutating
nothing. Live run: 5/5/5/5, invariants 2/2, org questions byte-for-byte
unchanged after.

Co-Authored-By: Claude <noreply@anthropic.com>
milstan pushed a commit that referenced this pull request Jun 24, 2026
…ds (#113)

* feat(core): retrieve org qualification methods + per-lead custom fields

Two new default-surface read composites resolving product#3768:

- leadbay_get_qualification_methods — returns the org's AI-agent
  qualification questions (the "qualification methods") with created_at +
  lang, plus the caller's is_admin flag and a web-app edit hint. Read-only
  for everyone; the API exposes no write endpoint for these questions.
- leadbay_get_lead_custom_fields — returns the CRM custom-field VALUES on a
  single lead as {id, name, type, value}. The lead payload embeds each
  field's definition (verified live), so no /crm/custom_fields join is
  needed; the catalog is fetched only as a defensive fallback. Fires
  LEAD_SEEN on read, in parity with the research tools.

Both were already partially reachable only via the ADVANCED-gated
get_taste_profile / list_mappable_fields (definitions only); the per-lead
custom_fields array was silently dropped (untyped on LeadPayload).

Adds LeadCustomFieldEntry + LeadPayload.custom_fields, two routing
templates, WORKFLOWS.md rows, and registry/audit entries
(COMPOSITE_FILE_TOOL_NAMES, TOOLS_WITH_ROUTING, output-schema
conformance CASES). Verified live end-to-end on the test org.

Co-Authored-By: Claude <noreply@anthropic.com>

* test(eval): add eval contracts for qualification-methods + lead-custom-fields

Adds the machine-readable yaml expected + yaml scenario blocks for
workflows #30 (Org qualification methods) and #31 (Per-lead custom-field
values) so /eval can run them. Live run: both 5/5/5/5, invariants green.

Co-Authored-By: Claude <noreply@anthropic.com>

* feat(core): update + delete CRM custom fields

Adds the modify surface for custom fields, completing the read+write set:

- leadbay_update_custom_field — rename and/or change type+config in place
  (POST /crm/custom_fields/{id} → 204, verified live). Partial-merge over the
  current definition so rename-only keeps the type and retype-only keeps the
  name. Same EXTERNAL_ID/PRICE config validation as create.
- leadbay_delete_custom_field — DELETE /crm/custom_fields/{id} → 204.
  Destructive (drops the field's values from every lead), so it requires an
  explicit confirm:true; without it the tool previews the field and does
  nothing. destructiveHint:true.

Both granular-shaped, registered in compositeWriteTools (default surface,
write-gated like create_custom_field). Conformance CASES + new unit test
files added; live update+delete round-trip verified.

Qualification methods intentionally get NO modify tool — the API exposes no
write endpoint for ai_agent_questions (every verb 404s); they stay read-only
with the web-app edit hint.

Co-Authored-By: Claude <noreply@anthropic.com>

* feat(core): modify org qualification methods (write)

The qualification-questions write endpoint DOES exist — it's the org root
POST /organizations/{orgId} with {ai_agent_lead_questions:[string,...]} → 204
(full-replace; confirmed live with the web app's exact payload). My earlier
404 was probing the wrong path (/ai_agent_questions).

Adds leadbay_set_qualification_methods:
- set / add / remove modes; reads the current list and posts the full
  resulting array (matches the full-replace endpoint).
- shrinking the list requires confirm:true (removing a question changes how
  every lead is scored); add does not.
- enforces the backend cap (max 5 questions) with an actionable hint instead
  of a raw 400.
- invalidates the taste-profile cache after a write.

Live-verified: add hits the 5-cap correctly; remove-without-confirm previews;
remove+restore round-trips cleanly (account left as found).

This supersedes the earlier "no write endpoint" note — qualification methods
are now fully modifiable, alongside custom fields.

Co-Authored-By: Claude <noreply@anthropic.com>

* test(eval): add eval contract for modify-qualification-methods (wf 32)

Adds workflow #32 (Modify qualification methods) exercising
leadbay_set_qualification_methods, and drops the now-stale "read-only"
note from #30. Scenario adds a question against an org already at the
5-question cap — exercises the write tool + cap handling while mutating
nothing. Live run: 5/5/5/5, invariants 2/2, org questions byte-for-byte
unchanged after.

Co-Authored-By: Claude <noreply@anthropic.com>

* test(eval): add eval contract for modify-custom-fields (wf 33)

Adds workflow #33 (Modify custom fields) exercising the full
create → update → delete lifecycle, including the delete confirm-gate.
Self-contained: the scenario creates a throwaway field, renames it, and
deletes it with confirm, so the run cleans up after itself. Live run:
5/5/5/5, invariants 3/3, catalog byte-for-byte unchanged after (only the
pre-existing field remains).

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(core): point get_qualification_methods at the modify tool

The read tool's description + admin hint still said editing happens in the
Leadbay web app with "no MCP edit tool yet" — stale since
leadbay_set_qualification_methods landed. Repoint the hint, is_admin doc,
description, and rendering footnote at leadbay_set_qualification_methods.

Confirmed against the backend repo: both modify surfaces (qualification
questions + custom fields) are authenticate("admin"), i.e. org-admin only —
which every user is for their own org, so the modify tools work for everyone
in practice. No per-lead custom-field VALUE write route exists (values flow
through the import pipeline only).

Co-Authored-By: Claude <noreply@anthropic.com>

* test(eval): make wf32 a self-restoring round-trip

The previous wf32 scenario ("add a question" against a capped list) let the
agent self-confirm a destructive removal to make room, mutating live data.
Rewrite it as a remove-then-readd round-trip on a single named question: it
nets back to the original set, exercises remove(confirm)+add, and never leaves
the org mutated. Live re-run: 5/5/5/5, question set byte-for-byte unchanged.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(mcp): reconstruct XDG_RUNTIME_DIR + DBUS for OAuth browser-open on Wayland/Snap

OAuth-on-install (.dxt) spawned xdg-open "successfully" but no tab opened on
Wayland + Snap-browser setups (the Ubuntu default). Claude Desktop strips
XDG_RUNTIME_DIR — which broke the existing WAYLAND_DISPLAY reconstruction (it
reads that dir) — and strips DBUS_SESSION_BUS_ADDRESS, so a Snap/Flatpak
browser couldn't be reached and the launch silently no-op'd.

browserLaunchEnv now rebuilds XDG_RUNTIME_DIR from /run/user/<uid> when stripped,
then derives WAYLAND_DISPLAY (wayland-N socket) and DBUS_SESSION_BUS_ADDRESS
(<runtimeDir>/bus) from it. Existing values are never overridden. Confirmed
live: with the fix a browser tab opens from a fully-stripped env; without it,
nothing. New test file oauth-browser-env-wayland.test.ts.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(mcp): reconstruct XAUTHORITY for OAuth browser-open on Wayland

Follow-up to the XDG_RUNTIME_DIR/WAYLAND/DBUS reconstruction: the browser
still failed to open from Claude Desktop's stripped child env because an
X11/XWayland browser (Chrome/Brave/Electron) needs the X authority cookie to
connect to the display. Without XAUTHORITY the X server rejects the client
("Authorization required... Missing X server") and the browser segfaults —
xdg-open returns 0, but no tab opens.

browserLaunchEnv now injects XAUTHORITY from the Mutter Xwayland cookie at
<runtimeDir>/.mutter-Xwaylandauth.*, falling back to ~/.Xauthority. Existing
value never overridden. Confirmed live: with XAUTHORITY the browser launches
instead of segfaulting. Test coverage extended.

Co-Authored-By: Claude <noreply@anthropic.com>

* chore(mcp): bump 0.23.0 -> 0.23.1 so .dxt reinstalls as a real update

Claude Desktop won't replace an installed extension with the same version
number, so the XAUTHORITY browser-open fix didn't take until the version
changed. Bumps package.json + server.json.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(core): sanitize custom-field config per type (500 on update/create)

leadbay_update_custom_field and leadbay_create_custom_field sent the config
object verbatim. The backend's per-type config models are strict
(PriceFieldConfig = {currency}, Date/DateTime = {format}, ExternalId =
{urlTemplate}, TEXT/NUMBER = none), so any extra key — a stale `format` left
from the previous type on a type CHANGE, both url_template + urlTemplate, or a
currency on a non-PRICE field — triggers a 500 "JSON deserialization error".
Reproduced live on staging: TEXT→PRICE with an over-broad config 500s.

Add sanitizeConfigForType (new _custom-field-config.ts) that narrows config to
exactly the key(s) the target type accepts, and apply it in both tools before
building the request body. Live-verified on staging: TEXT→PRICE/EUR now sends
{currency:"EUR"} and succeeds; full create→update→delete lifecycle clean.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(core): tolerate stringified custom-field config (PRICE currency dropped)

The agent passes config as a JSON STRING (e.g. config:'{"currency":"EUR"}'),
not an object. sanitizeConfigForType only read object properties, so a string
config yielded no currency → backend 400 "PRICE requires a currency config" on
a TEXT→PRICE update even though the rename landed. Observed live on staging.

sanitizeConfigForType now JSON-parses a string config before narrowing, and
both tools sanitize BEFORE the EXTERNAL_ID url_template check (so that check
sees the parsed value too). Live-verified: the exact stringified payload the
agent sent now narrows to {currency:"EUR"}.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(core): address PR review on qualification + custom-field tools

P2 — set_qualification_methods: gate confirm on the ACTUAL removed questions,
not on count. A remove+add or `set` that keeps the count the same still drops
a scoring question; the old `next.length < previousCount` check let that
through without confirm. Now computes the removed set and requires confirm
whenever any existing question would be dropped.

P2 — get_qualification_methods: fetch ai_agent_questions DIRECTLY instead of
via resolveTasteProfile (Promise.allSettled substitutes [] on a rejected
fetch). A transient backend/auth failure now surfaces as an error rather than
a false "no questions configured" that could lead a caller to overwrite real
questions.

P3 — create/update_custom_field: the tools parse a stringified config, so the
input schema now advertises it (type: ["object","string","null"]) and the
param types accept string — making the recovery path valid for schema-
validating clients.

New tests: same-count swap confirm gate, and fetch-failure-surfaces.

Co-Authored-By: Claude <noreply@anthropic.com>

* docs(mcp): add 0.23.1 CHANGELOG entry (review P3)

The package ships CHANGELOG.md but it started at 0.23.0, so consumers
installing 0.23.1 had no release notes for the new qualification-method +
custom-field tools. Adds the 0.23.1 entry.

Co-Authored-By: Claude <noreply@anthropic.com>

* refactor(core): rename qualification_methods → questions + move custom-field tools to composite/ (review)

Addresses Milan's PR review:

1. Naming — "qualification methods" introduced a new term for what the UI
   calls "qualification questions". Renamed both tools + all wording, files,
   templates, WORKFLOWS rows, tests, CHANGELOG:
   leadbay_get_qualification_methods → leadbay_get_qualification_questions
   leadbay_set_qualification_methods → leadbay_set_qualification_questions

2. Classification — "simple getters/setters are considered composites". Moved
   create/update/delete_custom_field (+ the _custom-field-config helper) from
   src/tools/ into src/composite/, and added them to COMPOSITE_FILE_TOOL_NAMES
   (so they carry the _triggered_by provenance mandate like other composites).

No behavior change; all gates green (core 463, mcp 466).

Co-Authored-By: Claude <noreply@anthropic.com>

* docs(core): align confirm schema with same-count swaps (review P3)

The set_qualification_questions schema + description said confirm:true was
required only when the list gets SHORTER, but the code (correctly) gates on
ANY dropped question — so an agent following the contract would make a
same-count swap without confirm and get a non-changing preview instead of the
edit. Reworded the `confirm` schema description, the tool body, and the
rendering note to state that dropping any existing question (incl. a same-count
swap or a `questions` replacement omitting a current question) needs confirm;
pure additions never do. Behavior unchanged; docs now match it.

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant